package com.pingan.pastry.registry;

import com.pingan.pastry.rpc.SPI;
import com.pingan.pastry.rpc.support.HttpInvoker;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;


import com.pingan.pastry.proxy.RemoteProxy;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

@Component
public class DynamicBeanRegistry implements BeanDefinitionRegistryPostProcessor {

    /*@Value("basePackage")*/
    private String basePackage = "com/pingan";

    public DynamicBeanRegistry() {
        super();
    }


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        try {
            Set<Class<?>> classSet = scanPackage(basePackage);
            for (Class<?> aClass : classSet) {
                //设置通用的beanDefinition
                AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
                beanDefinition.setBeanClass(RemoteProxy.class);
                beanDefinition.getPropertyValues().add("targetInterface", aClass);
                //创建委托
                HttpInvoker remoteInvoker = null;
                SPI annotation = aClass.getAnnotation(SPI.class);
                if (annotation != null) {
                    String host = annotation.host();
                    remoteInvoker = new HttpInvoker(host);
                }
                beanDefinition.getPropertyValues().add("invocationHandler", remoteInvoker);
                beanDefinitionRegistry.registerBeanDefinition(lowerBeanName(aClass.getName()), beanDefinition);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public String lowerBeanName(String classPath) {
        if (classPath != null) {
            String[] split = classPath.split("\\.");
            int lastIndex = split.length - 1;
            String className = split[lastIndex];
            String prefix = className.substring(0, 1);
            prefix = prefix.toLowerCase();
            String suffix = className.substring(1, className.length());
            return prefix + suffix;
        }
        return null;
    }

    public Set<Class<?>> scanPackage(String basePackage) throws Exception {
        //todo 先做基础的包扫描 后续在完善成配置化的包扫描
        Set<Class<?>> classSet = new HashSet<>();
        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(basePackage);
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            if ("file".equals(url.getProtocol())) {
                //获取根目录
                String currentPath = url.getFile();
                String encodeUrl = URLDecoder.decode(currentPath, "UTF-8");
                //获取class文件
                resolvingFileToClass(classSet, encodeUrl);
            }
        }
        return classSet;
    }

    public void resolvingFileToClass(Set<Class<?>> classSet, String packageName) throws ClassNotFoundException {
        File dir = new File(packageName);
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                //递归遍历
                resolvingFileToClass(classSet, packageName + "/" + file.getName());
            } else {
                String fileName = file.getName();
                if (fileName.endsWith(".class")) {
                    String className = fileName.substring(0, fileName.length() - 6);
                    int start = packageName.indexOf(basePackage);
                    String classPath = packageName.substring(start, packageName.length());
                    classPath = classPath.replaceAll("/", ".");
                    Class loadClass = Thread.currentThread().getContextClassLoader().loadClass(classPath + "." + className);
                    if (loadClass != null) {
                        SPI spi = (SPI) loadClass.getAnnotation(SPI.class);
                        if (spi != null) {
                            classSet.add(loadClass);
                        }
                    }
                }
            }
        }
    }


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    public static void main(String[] args) throws Exception {
        /*DynamicBeanRegistry dynamicBeanRegistry = new DynamicBeanRegistry();
        String name = "com.pingan.pastry.spi.OrderSPI";
        String s = dynamicBeanRegistry.lowerBeanName(name);
        System.out.println(s);*/
        /*String s = "F:\\studyProject\\pastry\\target\\classes\\com\\pingan\\pastry\\dao";
        System.out.println(s);
        s = s.replaceAll("\\\\", ".");
        System.out.println(s);
*/
       /* Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("com/pingan/pastry/common/annotation");
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            System.out.println(url.toString());
            System.out.println(url.getProtocol());
            System.out.println(URLDecoder.decode(url.getFile(), "UTF-8"));
            String path = URLDecoder.decode(url.getFile(), "UTF-8");
            File file = new File(path);
            System.out.println(file);
        }*/
        /*DynamicBeanRegistry dynamicBeanRegistry=new DynamicBeanRegistry();
        Set<Class<?>> classSet = dynamicBeanRegistry.scanPackage("com/pingan");
        for (Class<?> aClass : classSet) {
            System.out.println(aClass.getName());
        }*/

   /*     Class loadClass = Thread.currentThread().getContextClassLoader().loadClass("com.pingan.pastry.common.annotation.config.RedisConfig");
        System.out.println(loadClass.getName());*/
        long start = System.currentTimeMillis();
       /* System.out.println("startTime:" + start);*/
  /*      DynamicBeanRegistry dynamicBeanRegistry = new DynamicBeanRegistry();
        String userSPI = dynamicBeanRegistry.lowerBeanName("userSPI");
        System.out.println(userSPI);*/
       /* Set<Class<?>> classSet = dynamicBeanRegistry.scanPackage(dynamicBeanRegistry.basePackage);
        System.out.println("set: " + classSet.size());
        long end = System.currentTimeMillis();
        System.out.println("endTime:" + end);
        System.out.println(end - start);*/
    /*    String path="F:.studyProject.pastry.target.classes.com.pingan.pastry.common.annotation.Param";
        int start = path.indexOf("com.pingan");
        String substring = path.substring(start, path.length());
        System.out.println(substring);*/

    }
}
